﻿using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Runtime.Serialization;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;

namespace K9Nano.Share.Extensions
{
    public static class HttpClientExtensions
    {
        public static Task<T> PostAsync<T>(this HttpClient client, string uri, object data, CancellationToken cancellation)
        {
            return SendAsync<T>(client, HttpMethod.Post, uri, data, cancellation);
        }

        public static Task<T> PutAsync<T>(this HttpClient client, string uri, object data, CancellationToken cancellation)
        {
            return SendAsync<T>(client, HttpMethod.Put, uri, data, cancellation);
        }

        public static Task<T> DeleteAsync<T>(this HttpClient client, string uri, CancellationToken cancellation)
        {
            return SendAsync<T>(client, HttpMethod.Delete, uri, null, cancellation);
        }

        public static Task<T> DeleteAsync<T>(this HttpClient client, string uri, IDictionary<string, string> query, CancellationToken cancellation)
        {
            uri = QueryHelpers.AddQueryString(uri, query);
            return SendAsync<T>(client, HttpMethod.Delete, uri, null, cancellation);
        }

        public static Task<T> GetAsync<T>(this HttpClient client, string uri, CancellationToken cancellation)
        {
            return SendAsync<T>(client, HttpMethod.Get, uri, null, cancellation);
        }

        public static Task<T> GetAsync<T>(this HttpClient client, string uri,IDictionary<string, string> query, CancellationToken cancellation)
        {
            uri = QueryHelpers.AddQueryString(uri, query);
            return SendAsync<T>(client, HttpMethod.Get, uri, null, cancellation);
        }

        public static async Task<T> SendAsync<T>(this HttpClient client, HttpMethod method, string uri, object data, CancellationToken cancellation)
        {
            var request = new HttpRequestMessage(method, uri);
            if (data != null)
            {
                var json = JsonSerializer.Serialize(data);
                var content = new StringContent(json, Encoding.UTF8, "application/json");
                request.Content = content;
            }

            var response = await client.SendAsync(request, cancellation);
            var body = await response.Content.ReadAsStringAsync();
            if (!response.IsSuccessStatusCode)
            {
                throw new HttpRequestException($"{uri} {response.StatusCode}: {body}");
            }

            try
            {
                var result = JsonSerializer.Deserialize<T>(body);
                return result;
            }
            catch
            {
                throw new SerializationException($"Can not deserialize to {typeof(T)}: {body}");
            } 
        }
    }
}